package com.emp.test.springboottest.service;

import static com.alibaba.fastjson.JSON.toJSONString;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.emp.test.springboottest.domain.dao.OrderDao;
import com.emp.test.springboottest.domain.dao.PmStockDao;
import com.emp.test.springboottest.domain.dao.ProductDao;
import com.emp.test.springboottest.helper.ParamHelper;
import com.emp.test.springboottest.object.YhdOrdersGetParam;
import com.emp.test.springboottest.object.YhdProductAttributeGetParam;
import com.emp.test.springboottest.object.YhdProductStockGetParam;
import com.emp.test.springboottest.object.YhdRequestParam;
import com.emp.test.springboottest.object.YhdSearchProductsParam;
import com.emp.test.springboottest.object.YhdSysParam;
import com.yhd.YhdClient;
import com.yhd.object.ErrDetailInfo;
import com.yhd.object.ErrDetailInfoList;
import com.yhd.object.order.Order;
import com.yhd.object.product.PmStock;
import com.yhd.object.product.Product;
import com.yhd.request.basicAPI.BasicAreaGetRequest;
import com.yhd.request.order.OrdersGetRequest;
import com.yhd.request.product.GeneralProductsSearchRequest;
import com.yhd.request.product.ProductAttributeSingleGetRequest;
import com.yhd.request.product.ProductsStockGetRequest;
import com.yhd.request.product.ProductsWarehouseStocksGetRequest;
import com.yhd.response.basicAPI.BasicAreaGetResponse;
import com.yhd.response.order.OrdersGetResponse;
import com.yhd.response.product.GeneralProductsSearchResponse;
import com.yhd.response.product.ProductAttributeSingleGetResponse;
import com.yhd.response.product.ProductsStockGetResponse;
import com.yhd.response.product.ProductsWarehouseStocksGetResponse;

@Service
public class YhdService {
	
	final private String url = "http://openapi.yhd.com/app/api/rest/router";
	final private String appKey = "10210014081200002202";
	final private String secretKey = "8dad2a22c088f5e9689a4f466c1225d4";
	
	private static final int MAX_PORDUCTLIST_LENGTH = 100;//yhd.products.warehouse.stocks.get 接口最大能够接受的productIdList，或者outerIdList个数
	static final public String ERR_CODE_YHD_ORDERS_GET_NOT_FOUND = "yhd.orders.get.not_found";
	static final public String ERR_CODE_YHD_PRODUCTS_WAREHOUSE_STOCKS_GET_PARAM_ERROR = "yhd.products.warehouse.stocks.get.param.error"; //通过参数无法查询到结果
	private static final int DEFAULT_PAGEROW = 50;
	private static final String YHD_GENERAL_PRODUCTS_SEARCH_PROD_NO_FOUND = "yhd.general.products.search.prod_no_found";
	private static final String YHD_GENERAL_PRODUCTS_SEARCH_PROD_NOT_FOUND = "yhd.general.products.search.prod_not_found";
	
	YhdClient yhdClient = new YhdClient(url, appKey, secretKey);
	
	final static Logger logger = LoggerFactory.getLogger(YhdService.class);
	
	 @Resource(name = "orderDao")
	 OrderDao orderDao;
	 
	 @Resource(name = "productDao")
	 ProductDao productDao;
	 
	 @Resource(name = "pmStockDao")
	 PmStockDao pmStockDao;

	public List<Order> getOrders(YhdRequestParam<YhdOrdersGetParam> param){
		YhdOrdersGetParam ordersGetParam = null;
		YhdSysParam yhdSysParam = null;
		Assert.isTrue(param != null && (null != (ordersGetParam = param.getAppParam())  &&  (yhdSysParam = param.getSysParam()) != null ), "参数错误");
		
		List<Order> orders = new ArrayList<Order>();
		String sessionKey = yhdSysParam.getSessionKey();
		
		OrdersGetRequest request = new OrdersGetRequest();
		request.setOrderStatusList (ordersGetParam.getOrderStatusList());
		request.setDateType(ordersGetParam.getDateType());
		request.setPageRows(ordersGetParam.getPageRows());

		/**
		 * 传入时间可能大于最大时间间隔，需要分多次去取数据
		 */
		String time =  ordersGetParam.getStartTime();
		while(!ordersGetParam.getEndTime().equals(time)){
			request.setCurPage(ordersGetParam.getCurPage());
			request.setStartTime (time);
			request.setEndTime (time = ordersGetParam.getNextEndTime(time));
			
			this.getOrders(request,orders,sessionKey);
		}
		
		this.saveOrders(orders);
		
		return orders;
	}

	private List<Order> getOrders(OrdersGetRequest request, List<Order> orders, String sessionKey) {
		int curPage = request.getCurPage();
		int pageRow = request.getPageRows();
		
		logger.info("curPage : " + curPage);
		/**
		 * 数据可能不止一页，需要取完
		 */
		OrdersGetResponse response = null;
		do{
			response = yhdClient.excute(request, sessionKey);
			request.setCurPage(++curPage);
			this.getOrders(response,orders);
		}while((response != null) && (curPage - 1) * pageRow < response.getTotalCount());
		
		return orders;
	}

	@Transactional
	private void saveOrders(List<Order> orders) {
		orderDao.batchInsert(orders);
	}

	/**
	 * 从返回结果中取出订单信息，处理返回异常
	 * @param response
	 * @param orders
	 * @return
	 */
	private List<Order> getOrders(OrdersGetResponse response, List<Order> orders) {
		if(null == response) return orders ;
		
		List<ErrDetailInfo> err = null;
		
		if(response.getErrorCount() > 0 && (response.getErrInfoList() != null && (err = response.getErrInfoList().getErrDetailInfo()) != null)){
			Iterator<ErrDetailInfo> iter = err.iterator();
			while(iter.hasNext()){
				ErrDetailInfo errDetail = iter.next();
				logger.error(toJSONString(err));
				Assert.isTrue(ERR_CODE_YHD_ORDERS_GET_NOT_FOUND.equals(errDetail.getErrorCode()),toJSONString(err));
			}
			
			return orders;
		}
		
		orders.addAll(response.getOrderList().getOrder());
		return orders;
	}

	public BasicAreaGetResponse getBasicArea() {
		BasicAreaGetRequest request = new BasicAreaGetRequest();
		request.setLevel ( 1);
		return yhdClient.excute(request, "");
	}
	
	/**
	 * 用户搜索自己的产品信息，只支持普通产品
	 * @param param
	 * @return
	 */
	public GeneralProductsSearchResponse searchProducts(YhdRequestParam<YhdSearchProductsParam> param) {
		YhdSearchProductsParam yhdSearchProductsParam = null;
		YhdSysParam yhdSysParam = null;
		Assert.isTrue(param != null && (null != (yhdSearchProductsParam = param.getAppParam())  &&  (yhdSysParam = param.getSysParam()) != null ), "参数错误");
		
		GeneralProductsSearchRequest request = new GeneralProductsSearchRequest();
		if(yhdSearchProductsParam.getCurPage() != null) request.setCurPage(yhdSearchProductsParam.getCurPage());
		
		GeneralProductsSearchResponse response = yhdClient.excute(request, yhdSysParam.getSessionKey());
		
		return response;
	}
	
	@Transactional
	public List<Product> updateAllProducts(String sessionKey){
		List<Product> productList = new ArrayList<>();
		
		int curPage = 0;
		int pageRows = DEFAULT_PAGEROW;
		int totalCount = 0;
		
		YhdSearchProductsParam appParam = new YhdSearchProductsParam();
		appParam.setPageRows(pageRows);
		do{
			curPage++;
			appParam.setCurPage(curPage);
			GeneralProductsSearchResponse searchResponse = this.searchProducts(new YhdRequestParam<YhdSearchProductsParam>(
					YhdSysParam.getBuilder().
					setSessionKey(sessionKey).
					build(),
					appParam));
			
			totalCount = searchResponse.getTotalCount();
			productList.addAll(this.getProductList(searchResponse));
			
		}while(curPage * pageRows < totalCount);
		
		productDao.batchInsert(productList,sessionKey);
		
		return productList;
	}
	
	private List<? extends Product> getProductList(GeneralProductsSearchResponse searchResponse) {
		List<Product> ret = null;
		
		int errCount = 0;
		if((errCount = searchResponse.getErrorCount()) > 0){
			logger.info("getProductList : "+ errCount);
			ErrDetailInfoList errInfoList;
			List<ErrDetailInfo> errDetailInfo;
			if(null == (errInfoList = searchResponse.getErrInfoList()) || null == (errDetailInfo = errInfoList.getErrDetailInfo()) || errDetailInfo.isEmpty()){
				logger.error("getProductList :" + "errCount is 0 and errinfoList is null");
			}else{
				Iterator<ErrDetailInfo> iter = errDetailInfo.iterator();
				while(iter.hasNext()){
					ErrDetailInfo err = iter.next();
					Assert.isTrue(YHD_GENERAL_PRODUCTS_SEARCH_PROD_NO_FOUND.equals(err.getErrorCode()) || YHD_GENERAL_PRODUCTS_SEARCH_PROD_NOT_FOUND.equals(err.getErrorCode()), toJSONString(err));
					logger.info(toJSONString(err));
				}
			}
		}
		
		return (null == (ret = searchResponse.getProductList().getProduct()) ? new ArrayList<>() : ret);
	}

	public ProductAttributeSingleGetResponse getSingleProductAttribute(YhdRequestParam<YhdProductAttributeGetParam> param){
		YhdProductAttributeGetParam yhdProductAttributeGetParam = null;
		YhdSysParam yhdSysParam = null;
		Assert.isTrue(param != null && (null != (yhdProductAttributeGetParam = param.getAppParam())  &&  (yhdSysParam = param.getSysParam()) != null ), "参数错误");
		
		ProductAttributeSingleGetRequest request = new ProductAttributeSingleGetRequest();
		request.setProductId ( yhdProductAttributeGetParam.getProductId());
		ProductAttributeSingleGetResponse response = yhdClient.excute(request, yhdSysParam.getSessionKey());
		
		return response;
	}
	
	public ProductsStockGetResponse getStocks(YhdRequestParam<YhdProductStockGetParam> param){
		YhdProductStockGetParam yhdProductStockGetParam = null;
		YhdSysParam yhdSysParam = null;
		Assert.isTrue(param != null && (null != (yhdProductStockGetParam = param.getAppParam())  &&  (yhdSysParam = param.getSysParam()) != null ), "参数错误");

		ProductsStockGetRequest request = new ProductsStockGetRequest();
		request.setProductIdList (yhdProductStockGetParam.getProductIdList());
		ProductsStockGetResponse response = yhdClient.excute(request, yhdSysParam.getSessionKey());
		
		return response;
	}
	
	public List<PmStock> getWarehouseStocks(YhdRequestParam<YhdProductStockGetParam> param){
		YhdProductStockGetParam yhdProductStockGetParam = null;
		YhdSysParam yhdSysParam = null;
		Assert.isTrue(param != null && (null != (yhdProductStockGetParam = param.getAppParam())  &&  (yhdSysParam = param.getSysParam()) != null ), "参数错误");

		String productList = yhdProductStockGetParam.getProductIdList();
		ProductsWarehouseStocksGetRequest request = new ProductsWarehouseStocksGetRequest();
		List<PmStock>  pmStock = new ArrayList<>();
		for(int index = 0, nextIndex = 0, endIndex = productList.length() - 1; index < endIndex; index = nextIndex + 2){
			
			nextIndex = ParamHelper.getNext(productList, index, ',', MAX_PORDUCTLIST_LENGTH);
			request.setProductIdList ( productList.substring(index, nextIndex));
			ProductsWarehouseStocksGetResponse response = yhdClient.excute(request, yhdSysParam.getSessionKey());
			pmStock.addAll(this.getWarhoseStocks(response));
		}
		
		return pmStock;
	}
	
	private List<? extends PmStock> getWarhoseStocks(ProductsWarehouseStocksGetResponse response) {
		List<PmStock> ret = null;
		
		int errCount;
		if((errCount = response.getErrorCount()) != 0){
			logger.info("错误次数 " + toJSONString(errCount));
			
			ErrDetailInfoList errInfoList = null;
			List<ErrDetailInfo> errInfos = null;
			if(null == (errInfoList = response.getErrInfoList()) || null == (errInfos = errInfoList.getErrDetailInfo())){
				logger.error("getWarhoseStocks getErrorCount is not 0 but getErrInfoList is null");
			}else{
				Iterator<ErrDetailInfo> iter = errInfos.iterator();
				while(iter.hasNext()){
					ErrDetailInfo err = iter.next();
//					Assert.isTrue(ERR_CODE_YHD_PRODUCTS_WAREHOUSE_STOCKS_GET_PARAM_ERROR.equals(err.getErrorCode()), toJSONString(err));
					logger.info("查询结果为空： " + toJSONString(err));
				}
			}
		}
		
		return null == (ret = response.getPmStockList().getPmStock()) ? new ArrayList<>() : ret;
	}

//	private <T> boolean getParam(YhdRequestParam<T> param, YhdSysParam yhdSysParam,
//			T appParam) {
//		return param != null && (null != (appParam = param.getAppParam())  &&  (yhdSysParam = param.getSysParam()) != null );
//	}

	@Transactional
	public List<PmStock> updateAllStocks(String sessionKey){
		Assert.hasText(sessionKey, "用户sessionKey id 为空");
		
		YhdProductStockGetParam appParam = new YhdProductStockGetParam();
		appParam.setProductIdList(productDao.getAllid(sessionKey));
		
		List<PmStock> stocks = this.getWarehouseStocks(new YhdRequestParam<YhdProductStockGetParam>(
				YhdSysParam.getBuilder().
				setSessionKey(sessionKey).
				build(),
				appParam));
		
		logger.info(toJSONString(stocks));
		pmStockDao.batchInsert(stocks, sessionKey);
		
		return stocks;
	}
	
	
}
